/**
 * 将日期转换为相对时间字符串
 * @param {Date|string|number} date - 要格式化的日期，可以是Date对象、时间戳或日期字符串
 * @returns {string} 格式化后的相对时间字符串:
 * - '无效日期' - 如果输入的日期无效
 * - '未来时间' - 如果日期在当前时间之后
 * - '刚刚' - 如果时间差小于1分钟
 * - 'X分钟前' - 如果时间差小于1小时
 * - 'X小时前' - 如果时间差小于24小时
 * - 'X天前' - 如果时间差小于30天
 * - 具体日期(YYYY/MM/DD格式) - 如果时间差大于等于30天
 * @example
 * formatTime('2023-11-20') // 返回 "3天前"
 * formatTime(new Date()) // 返回 "刚刚"
 * formatTime('invalid date') // 返回 "无效日期"
 * formatTime('2024-12-31') // 返回 "未来时间"
 */
export const formatTime = (date) => {
  // 获取当前时间的Date对象作为基准时间
  // 用于计算与目标时间的差值
  const now = new Date()

  // 将传入的参数转换为Date对象
  // 支持多种输入格式：Date对象、时间戳(number)、日期字符串(string)
  // new Date() 构造函数会自动识别并转换这些格式
  const targetDate = new Date(date)

  // 输入验证：检查转换后的Date对象是否有效
  // isNaN(targetDate.getTime()) 用于判断日期是否有效
  // 无效的日期调用getTime()会返回NaN
  if (isNaN(targetDate.getTime())) {
    return '无效日期'
  }

  // 计算时间差（单位：毫秒）
  // 当前时间减去目标时间，得到时间间隔
  // 如果结果为正数，说明目标时间在过去；如果为负数，说明目标时间在未来
  const diff = now - targetDate

  // 边界条件处理：如果目标时间在未来
  // diff < 0 表示目标时间比当前时间晚
  if (diff < 0) {
    return '未来时间'
  }

  // 时间单位转换：将毫秒差值转换为不同的时间单位

  // 转换为分钟数
  // 1分钟 = 60秒 = 60 × 1000毫秒 = 60000毫秒
  // Math.floor() 向下取整，只保留完整的分钟数
  const minutes = Math.floor(diff / 60000)

  // 转换为小时数
  // 1小时 = 60分钟 = 3600秒 = 3600 × 1000毫秒 = 3600000毫秒
  // Math.floor() 向下取整，只保留完整的小时数
  const hours = Math.floor(diff / 3600000)

  // 转换为天数
  // 1天 = 24小时 = 1440分钟 = 86400秒 = 86400 × 1000毫秒 = 86400000毫秒
  // Math.floor() 向下取整，只保留完整的天数
  const days = Math.floor(diff / 86400000)

  // 根据时间差的大小返回相应的相对时间描述
  // 按照从小到大的时间间隔进行判断

  // 时间差小于1分钟：显示"刚刚"
  // 这包括0-59秒的时间范围
  if (minutes < 1) return '刚刚'

  // 时间差在1分钟到1小时之间：显示"X分钟前"
  // 这包括1-59分钟的时间范围
  if (minutes < 60) return `${minutes}分钟前`

  // 时间差在1小时到24小时之间：显示"X小时前"
  // 这包括1-23小时的时间范围
  if (hours < 24) return `${hours}小时前`

  // 时间差在1天到30天之间：显示"X天前"
  // 这包括1-29天的时间范围
  if (days < 30) return `${days}天前`

  // 时间差大于等于30天：显示具体的日期
  // 使用toLocaleDateString('zh-CN')方法格式化为中文日期格式
  // 返回格式类似：2023/10/23
  return targetDate.toLocaleDateString('zh-CN')
}

/*
补充说明：

1. 时间计算常量：
   - 1秒 = 1000毫秒
   - 1分钟 = 60秒 = 60000毫秒
   - 1小时 = 60分钟 = 3600000毫秒
   - 1天 = 24小时 = 86400000毫秒

2. Math.floor() 的作用：
   - 向下取整，确保得到完整的时间单位
   - 例如：1.9小时会被处理为1小时

3. 判断逻辑的优先级：
   - 从最小的时间单位开始判断
   - 一旦满足条件就立即返回，不会继续执行后续判断

4. 支持的输入格式：
   - Date对象：new Date()
   - 时间戳：1698049825123
   - ISO字符串：'2023-10-23T06:30:25.000Z'
   - 日期字符串：'2023-10-23'、'2023/10/23'等

5. 错误处理：
   - 无效输入返回'无效日期'
   - 未来时间返回'未来时间'
   - 确保函数的健壮性
*/

/**
 * 将日期对象格式化为 YYYY-MM-DD HH:mm:ss 格式的字符串
 * @param {Date} date - 要格式化的日期对象，默认为当前时间
 * @returns {string} 格式化后的日期时间字符串
 */
export function formatDateTime(date = new Date()) {
  /**
   * 辅助函数：将数字补零到两位数
   * @param {number} num - 需要补零的数字
   * @returns {string} 补零后的字符串（至少两位数）
   * 例如：pad(5) => "05", pad(12) => "12"
   */
  const pad = (num) => String(num).padStart(2, '0')

  // 获取年份（四位数）
  // getFullYear() 返回完整的年份，如 2024
  const year = date.getFullYear()

  // 获取月份并补零
  // getMonth() 返回 0-11，所以需要 +1 得到实际月份 1-12
  // 然后使用 pad 函数确保是两位数格式
  const month = pad(date.getMonth() + 1)

  // 获取日期并补零
  // getDate() 返回月份中的第几天 (1-31)
  const day = pad(date.getDate())

  // 获取小时并补零
  // getHours() 返回 24 小时制的小时数 (0-23)
  const hours = pad(date.getHours())

  // 获取分钟并补零
  // getMinutes() 返回分钟数 (0-59)
  const minutes = pad(date.getMinutes())

  // 获取秒数并补零
  // getSeconds() 返回秒数 (0-59)
  const seconds = pad(date.getSeconds())

  // 使用模板字符串组合所有部分
  // 格式：YYYY-MM-DD HH:mm:ss
  // 日期部分用 "-" 分隔，时间部分用 ":" 分隔，日期和时间之间用空格分隔
  return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`
}

// 使用示例
// console.log(formatDateTime()); // 输出当前时间，例如：2024-01-15 14:30:25

// console.log(formatDateTime(new Date('2017-08-19 20:28:58'))); // 输出指定时间：2017-08-19 20:28:58

// // 其他使用示例：
// console.log(formatDateTime(new Date())); // 当前时间
// console.log(formatDateTime(new Date('2023-12-25'))); // 圣诞节：2023-12-25 00:00:00
// console.log(formatDateTime(new Date(2024, 0, 1, 12, 30, 45))); // 2024年1月1日 12:30:45
